﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Xodeuz.SP.Common
{
    public enum QueryType
    {
        LessThanOrEqual = 0,
        GreaterThanOrEqual = 1,
        Contains = 2,
        NotContains = 3,
        Equals = 4,
        NotEquals = 5,
        LessThan = 6, 
        GreaterThan = 7,
    }

    public enum CamlBuilderComplexity
    {
        Simple,
        Complex
    }

    public class CamlBuilder
    {
        private static readonly string[] QueryTypes =
        {
            "<Leq>{0}</Leq>", "<Geq>{0}</Geq>", "<Contains>{0}</Contains>", "<NotContains>{0}</NotContains>",
            "<Eq>{0}</Eq>", "<Neq>{0}</Neq>", "<Lt>{0}</Lt>", "<Gt>{0}</Gt>"
        };
        private const string QUERY = "<Query>{0}</Query>";
        private const string AND = "<And>{0}</And>";
        private const string OR = "<Or>{0}</Or>";
        private const string WHERE = "<Where>{0}</Where>";
        private const string FIELDREF = "<FieldRef Name='{0}' />";
        private const string VALUE = "<Value Type='{0}'>{1}</Value>";

        private StringBuilder _builder;
        private List<String> _or;
        private List<String> _and; 

        private CamlBuilder()
        {
            _builder = new StringBuilder();
            _or = new List<string>();
            _and = new List<string>();
        }

        public CamlBuilder Or(QueryType type, String fieldName, String valueType, object value)
        {
            String fieldRef = String.Format(FIELDREF, fieldName);
            String valueRef = String.Format(VALUE, valueType, value);

            _or.Add(String.Format(QueryTypes[(int)type], fieldRef + valueRef));
            return this;
        }

        public CamlBuilder And(QueryType type, String fieldName, String valueType, object value)
        {
            String fieldRef = String.Format(FIELDREF, fieldName);
            String valueRef = String.Format(VALUE, valueType, value);

            _and.Add(String.Format(QueryTypes[(int)type], fieldRef + valueRef));
            return this;
        }

        private string CombineQueries()
        {
            String orQuery = "";
            String andQuery = "";

            if (_or.Count != 0)
            {
                _or.ForEach(q =>  orQuery += q );
                orQuery = String.Format(OR, orQuery);
            }

            if (_and.Count != 0)
            {
                _and.ForEach(q => andQuery += q);
                andQuery = String.Format(AND, andQuery);
            }

            var fullQuery = String.IsNullOrEmpty(orQuery) || String.IsNullOrEmpty(andQuery)
                ? andQuery + orQuery
                : string.Format(AND, andQuery + orQuery);

            return String.Format(WHERE, fullQuery);
        }
        

        public String Query
        {
            get { return CombineQueries(); }
        }

        public static CamlBuilder Build()
        {
            return new CamlBuilder();
        }

        
    }
}
